home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 1995 #5 & #6
/
Amiga Plus CD - 1995 - No. 5 and 6.iso
/
pd
/
serien
/
purity
/
nr.12
/
workshop
/
pascalkursii.txt
< prev
next >
Wrap
Text File
|
1995-04-21
|
17KB
|
446 lines
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ Systemprogrammierung in PCQ-Pascal +
+ Kurs für AMIGAGadget und Purity- Teil II +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Bisherige Kursteile :
Teil I : Voraussetzungen,Screens,Windows
Und hallo !
Und hier wären wir zum zweiten Teil dieses tollen Kurses !
Alle da ? Jaaaa !! Gut. Also, ich muß noch eine Entschuldigung
anbringen : ähm...stotter...die CloseWork-Routine war ein leichter Schuß
in den Ofen.... Man sollte erst das Window und dann den Screen
schließen. Funktioniert hat es aber trotzdem.
Beim letzten Mal haben wir Screens und Windows behandelt. Wir können
jetzt also unsern eigenen Bildschirm aufmachen.
So weit, so gut. Doch was machen wir jetzt mit dem ganzen ?
Das Zeug liegt leer rum und stört nur. Die Dinger müssen doch zu was
zu gebrauchen sein. Ein bißchen drin rummalen und Text ausgeben wäre
gar nicht uninteressant. Deshalb
III. Einfache Grafikausgabe
Bisher sind wir ja ganz gut mit der "Intuition.Library" ausgekommen.
Das reicht nun aber nicht mehr. Wir brauchen etwas, was uns hilft,
unsere optischen Vorstellungen zu verwirklichen - die "Graphics.Library".
Was die Intuition-Library für Screens und Windows ist, ist die
Graphics-Library für Rastports und Bitmaps. Was,was,was ?? Das war
zugegebenermaßen gemein von mir - einen neuen Begriff mit zwei anderen
neuen zu erklären. Ein Rastport ist ein Graphics-Element, das den
vereinfachten Zugriff auf Bitmaps ermöglicht. Bitmap nennt man die
Verknüpfung mehrerer Bitplanes (siehe Teil 1 !!). Die Verbindung
zwischen Graphics und Intuition ist z.B. das Window, das wiederum
einen vereinfachten Zugriff auf Rastports ermöglicht. Genug der grauen
Theorie. Wie malen wir jetzt einen Punkt in unser Window ? Ganz einfach :
WritePixel (window^.RPort,xk,yk)
Man benötigt einen Zeiger auf das Window und übergibt der WritePixel
-Routine die x- und die y-Koordinate des zu zeichnenden Punktes.
Fertig.
Wer jetzt suchend um sich schaut und nicht versteht, was x- und
y-Koordinaten sind und noch nie so etwas gegessen hat, dem sei
geholfen. Man kann sich ein Window als Koordinatenkreuz (mal wieder
in der Schule gepennt ??) vorstellen. Durch so ein Koordinatenkreuz
lässt sich jeder Punkt einer Fläche als Zahlenpaar beschrieben. Die
x-Koordinate beschreibt die Entfernung vom linken Rand, die y-Koordinate
normalerweise vom unteren Rand. Gemeinerweise ist das beim Computer nicht
so. Der Ursprung (0/0) liegt hier nicht links unten, sondern links
oben. Aha ! Also zeigt die y-Koordinate den Abstand vom oberen Rand.
Logisch, oder ? Wenn wir ein Window der Breite 400 aufgemacht haben, dann
gehen unsere x-Koordinaten von 0 bis 400. Aha ! Feine Sache, oder ?
Eins sollte man aber beachten : Wenn man x-Werte von 0 oder 1, bzw.
von 399 oder 400 verwendet, dann würde in so einem Window (400er Breite)
der Rahmen beschädigt. Also : aufpassen mit dem Rand (auch gerade die
Titelleiste !!).
Das wär's dann wohl.
Also legen wir doch gleich mal los ....
HAAAAAAALT !!! Reingefallen ! Wir brauchen noch etwas ganz Wichtiges !
Wir wollen ja die Graphics-LIBRARY benutzen ! Und was müssen wir machen,
damit wir sie auch verwenden können ? Richtig - sie muß erstmal aufgemacht
werden. Da bietet uns das Include-File "Exec/Libraries.I" eine brauchbare
Routine : OpenLibrary. Sie benötigt den Namen der Library und die
Versionsnummer, die die Library mindestens haben muß. Als Rückgabewert
erhalten wir einen Pointer auf eine Library. Was wir nun mit dem machen ?
Ganz einfach. PCQ erwartet ihn an einer ganz bestimmten Stelle.
Nämlich in der Variablen "GfxBase", die im File "Graphics/Graphics.I"
deklariert wird. Als dann, nun können wir wohl beginnen...
Weit gefehlt ! WritePixel bringt einfach einen Punkt auf den Bildschirm.
Wir wollen aber einen in der Vordergrundfarbe und nicht etwa einen
in der Hintergrundfarbe !! Also müssen wir die Zeichenfarbe festlegen :
SetAPen (window^.RPort , farbregister)
Farbregister 0 wäre die Hintergrundfarbe. Wir nehmen also Farbregister 1.
Aber jetzt geht es los ! Wieder falsch. Schaut man nämlich mal in das
File "Graphics.I", so sieht man, daß die Befehle hier nicht sind.
Sie müssen also woanders sein. Gesucht und gefunden im File "Pens.i".
Und jetzt, ohne lange drumherum zu reden :
Program KursProgramm (input , output);
{ Listing für den AMIGAGadget/Purity - Pascalkurs , }
{ Erste Schritte in der Grafikprogrammierung }
{$I "Include:Intuition/Intuition.I" }
{$I "Include:Exec/Libraries.I" }
{$I "Include:Graphics/Graphics.I" }
{$I "Include:Libraries/Dos.I" }
{$I "Include:Graphics/Pens.I" }
VAR
myscreen : ScreenPtr;
mywindow : WindowPtr;
PROCEDURE CloseDisplay;
{ Sollte ein Teil des Displays offen sein, dann wird er von }
{ dieser Routine geschlossen. }
BEGIN
IF mywindow<>NIL THEN
CloseWindow (mywindow);
IF myscreen<>NIL THEN
CloseScreen (myscreen);
IF GfxBase<>NIL THEN
CloseLibrary (GfxBase);
END;
PROCEDURE BreakProgram (reason : STRING);
{ Diese Routine schließt alles bisher geöffnete, druckt den }
{ Fehlergrund aus und bricht dann das Programm ab. }
BEGIN
CloseDisplay;
WRITELN ('Program error : ',reason);
Exit (42);
END;
PROCEDURE OpenLibs;
CONST GfxName : String = "graphics.library";
BEGIN
GfxBase:=OpenLibrary (GfxName,0);
END;
PROCEDURE OpenDisplay;
{ Diese Routine erstellt ein Display. }
CONST
mynewscreen : NewScreen = (0,0,640,256,2,0,1,HIRES,
CUSTOMSCREEN_f,NIL,
"UnserGrafikscreen",NIL,NIL);
mynewwindow : NewWindow = (0,0,400,200,0,1,0,
SMART_REFRESH+ACTIVATE+
WINDOWDRAG,NIL,NIL,"Unser Grafikwindow",
NIL,NIL,0,0,0,0,CUSTOMSCREEN_f);
BEGIN
myscreen := OpenScreen (Adr(mynewscreen));
IF myscreen=NIL THEN BreakProgram ("Couldn't open Screen");
mynewwindow.Screen:=myscreen;
mywindow := OpenWindow (Adr(mynewwindow));
IF mywindow=NIL THEN BreakProgram ("Couldn't open Window");
END;
PROCEDURE WarteEinWenig;
{ Also, das mit den FOR-Schleifen ist mir jetzt doch zu }
{ unelegant ! Wir binden daher also "libraries/dos.i" ein }
{ und benutzen nun den Befehl Delay (taktzyklen). }
BEGIN
Delay (500);
END;
PROCEDURE ZeichneEtwas;
VAR ze1 : INTEGER;
BEGIN
SetAPen (mywindow^.RPort,1);
FOR ze1:=1 TO 200 DO
WritePixel (mywindow^.RPort,ze1*2,ze1);
{ zeichnet eine löchrige schräge Linie }
END;
BEGIN
OpenLibs;
OpenDisplay;
ZeichneEtwas;
WarteEinWenig;
CloseDisplay;
END.
Sieht ja schon ganz schnucklig aus. Oder ? Doch es wäre etwas mühsam, wenn
man nur den Befehl WritePixel hätte, um Grafiken zu erstellen....
Also gibt es noch ein paar andere wichtige.
Einen kurzen Überblick über die, die man am häufigsten braucht :
Move (window^.RPort , x , y) - bewegt den Grafikcursor an eine Position
des Rastports, ohne etwas zu zeichnen.
WritePixel bewegt den Grafikcursor zwar
auch, zeichnet aber einen Punkt
Draw (window^.RPort , x , y) - zeichnet eine Linie von der Position des
Grafikcursors zu den neuen Koordinaten
RectFill (window^.RPort ,
xmin,ymin,xmax,ymax)- zeichnet ein ausgefülltes Rechteck mit den
vier Eckpunkten
E1 (xmin / ymin)
E2 (xmin / ymax)
E3 (xmax / ymax)
E4 (xmax / ymin)
DrawEllipse (window^.RPort,
cx , cy , a , b) - zeichnet eine Ellipse mit dem Mittelpunkt
M (cx / cy) und einem maximalen Radius in
x-Ausdehnung von a Pixeln und in
y-Ausdehnung von b Pixeln
DrawCircle (window^.RPort ,
cx , cy , a ) - Sonderfall von DrawEllipse. X- und y-Radius
sind hier gleich. Aber Achtung : Gerade bei
der sogenannten Med-Res-Auflösung (640*256)
sind das bei weitem keine Kreise mehr !!
ReadPixel (window^.RPort,x,y)- liefert als Rückgabewert das Farbregister
des Bildschirmpunktes an der Stelle P (x/y)
Das sollte für's erste mal reichen. In der nächsten Folge kommen dann
noch ein paar dazu. Es gibt noch weitaus mehr, die aber für den Einstieg
zu weit führen und zu umfassende Kenntnisse erfordern, als sie hier in
den wenigen Zeilen vermittelt werden können.
Was allerdings einen großen Platz einnehmen wird sind selbstgeschriebene
Prozeduren, die man dann als Grafikbefehle einsetzen kann. So brauchen
wir ganz dringend einen, um Linien zu ziehen. Sinnigerweise sollten wir
ihn Line nennen. Eine Linie hat einen Anfangs- und einen Endpunkt.
Diese müssen übergeben werden. Außerdem natürlich der RastPort.
Also, jeder mal ran an einen Stift und schnell so eine Prozedur
entworfen.......
Fertig ? Gut. Sie sollte etwa so aussehen :
PROCEDURE Line (rp : Address ; xs , ys , xe , ye : Short);
BEGIN
Move (rp , xs , ys); Draw (rp , xe , ye);
END;
Einfach, oder ? Und nun gibt es noch eine gewisse Form, die man oft auf
Computerbildschirmen sieht....ja....ja....genau, das Rechteck. Um
ausgefüllte Exemplare der Gattung zu bekommen, haben wir ja den
RectFill-Befehl. Wie zeichnen wir nun aber nur den Rahmen ??
Eine neue Prozedur muß her !
PROCEDURE Box (rp : Address ; xs , ys , xe , ye : Short);
BEGIN
Line (rp,xs,ys,xe,ys); Line (rp,xe,ys,xe,ye);
Line (rp,xe,ye,xs,ye); Line (rp,xs,ye,xs,ys);
END;
In Sachen Taktzyklen ausnützen sicher nicht das Optimum. Dafür anschaulich
und kurz.
Nun wollen wir mal kräftig alle unsere Kenntnisse ausspielen. Ein Multi
-Grafik-Programm ! Vier Fenster, in denen jeweils andere Grafiken
gezeichnet werden sollen. Also dann : Vorhang auf !
Program KursProgramm (input , output);
{ Listing für den AMIGAGadget/Purity - Pascalkurs , }
{ Zweite Schritte in der Grafikprogrammierung }
{$I "Include:Intuition/Intuition.I" }
{$I "Include:Exec/Libraries.I" }
{$I "Include:Graphics/Graphics.I" }
{$I "Include:Libraries/Dos.I" }
{$I "Include:Graphics/Pens.I" }
VAR
myscreen : ScreenPtr;
mywindow : ARRAY [1..4] OF WindowPtr;
PROCEDURE Line (rp : Address ; xs , ys , xe , ye : Short);
BEGIN
Move (rp , xs , ys); Draw (rp , xe , ye);
END;
PROCEDURE Box (rp : Address ; xs , ys , xe , ye : Short);
BEGIN
Line (rp,xs,ys,xe,ys); Line (rp,xe,ys,xe,ye);
Line (rp,xe,ye,xs,ye); Line (rp,xs,ye,xs,ys);
END;
PROCEDURE CloseDisplay;
VAR i : Integer;
{ Sollte ein Teil des Displays offen sein, dann wird er von }
{ dieser Routine geschlossen. }
BEGIN
FOR i:=1 TO 4 DO
IF mywindow[i]<>NIL THEN
CloseWindow (mywindow[i]);
IF myscreen<>NIL THEN
CloseScreen (myscreen);
IF GfxBase<>NIL THEN
CloseLibrary (GfxBase);
END;
PROCEDURE BreakProgram (reason : STRING);
{ Diese Routine schließt alles bisher geöffnete, druckt den }
{ Fehlergrund aus und bricht dann das Programm ab. }
BEGIN
CloseDisplay;
WRITELN ('Program error : ',reason);
Exit (42);
END;
PROCEDURE OpenLibs;
CONST GraphicName : String = "graphics.library";
BEGIN
GfxBase:=OpenLibrary (GraphicName,0);
END;
PROCEDURE OpenDisplay;
{ Diese Routine erstellt ein Display. }
CONST
mynewscreen : NewScreen = (0,0,640,256,1,0,1,HIRES,
CUSTOMSCREEN_f,NIL,
"Die MultiGrafik-Show !",NIL,NIL);
NewWin1 : NewWindow = (0,0,320,128,0,1,0,SMART_REFRESH+WINDOWDRAG+
ACTIVATE+SMART_REFRESH,NIL,NIL,"Multi-GFX-Show 1",
NIL,NIL,0,0,0,0,CUSTOMSCREEN_f);
NewWin2 : NewWindow = (320,0,320,128,0,1,0,SMART_REFRESH+WINDOWDRAG+
ACTIVATE+SMART_REFRESH,NIL,NIL,"Multi-GFX-Show 2",
NIL,NIL,0,0,0,0,CUSTOMSCREEN_f);
NewWin3 : NewWindow = (0,128,320,128,0,1,0,SMART_REFRESH+WINDOWDRAG+
ACTIVATE+SMART_REFRESH,NIL,NIL,"Multi-GFX-Show 3",
NIL,NIL,0,0,0,0,CUSTOMSCREEN_f);
NewWin4 : NewWindow = (320,128,320,128,0,1,0,SMART_REFRESH+WINDOWDRAG+
ACTIVATE+SMART_REFRESH,NIL,NIL,"Multi-GFX-Show 4",
NIL,NIL,0,0,0,0,CUSTOMSCREEN_f);
BEGIN
myscreen := OpenScreen (Adr(mynewscreen));
IF myscreen=NIL THEN BreakProgram ("Couldn't open Screen");
NewWin1.Screen:=myscreen;
NewWin2.Screen:=myscreen;
NewWin3.Screen:=myscreen;
NewWin4.Screen:=myscreen;
mywindow[1] := OpenWindow (Adr(NewWin1));
mywindow[2] := OpenWindow (Adr(NewWin2));
mywindow[3] := OpenWindow (Adr(NewWin3));
mywindow[4] := OpenWindow (Adr(NewWin4));
IF mywindow[4]=NIL THEN BreakProgram ("Couldn't open Window");
END;
PROCEDURE WarteEinWenig;
BEGIN
Delay (1000);
END;
PROCEDURE MultiShow;
VAR ze1 : INTEGER;
r : Real;
{ Wir durchlaufen eine Schleife, in der für jedes Window ein }
{ Zeichenbefehl aufgerufen wird. }
BEGIN
FOR ze1:=1 TO 4 DO
SetAPen (mywindow[ze1]^.RPort,1);
FOR ze1:=0 TO 50 DO
BEGIN
{ Zeichenbefehl für Window 1 }
RectFill (mywindow[1]^.RPort,2+(ze1*3),12+(ze1),
2+(ze1*5),24+(ze1*2));
IF (ze1 / 2)<>(ze1 DIV 2) THEN
BEGIN
SetAPen (mywindow[1]^.RPort,0);
RectFill (mywindow[1]^.RPort,3+(ze1*3),13+(ze1),
1+(ze1*5),23+(ze1*2));
SetAPen (mywindow[1]^.RPort,1);
END;
{ Zeichenbefehl für Window 2 }
Line (mywindow[2]^.RPort,10+(6*ze1),20,310-(6*ze1),120);
Line (mywindow[2]^.RPort,10,20+(ze1*2),310,120-(ze1*2));
{ Zeichenbefehl für Window 3 }
r:=ze1/50*3.141;
Box(mywindow[3]^.RPort,160+TRUNC(Cos(r)*120),60+TRUNC(Sin(r)*50),
180+TRUNC(Cos(r)*120),70+TRUNC(Sin(r)*50));
{ Zeichenbefehl für Window 4 }
DrawEllipse (mywindow[4]^.RPort,160,64,ze1*3,ze1);
END;
END;
BEGIN
OpenLibs;
OpenDisplay;
MultiShow;
WarteEinWenig;
CloseDisplay;
END.
Boah, oder ???
Zu dem Programm muß ich noch etwas sagen : ich habe jetzt 3 (!!!!) Stunden
lang alle möglichen Programmteile umgestellt, immer wieder neu compiliert
und muß zugeben : ich stehe vor einem Rätsel. Nach dem Compilieren
läuft das Programm. Wenn ich mit meiner Pascal-Disk neu boote läuft's
meistens nicht.... Jetzt hab ich mit meiner Systemdisk gebootet und
es läuft - weiß der Geier, was da nicht richtig ist ! (Schwache Leistung,
ich geb's ja zu, aber ich hab eigentlich heute noch was anderes vor....)
Das sollte wohl für diesmal wieder genügen. Probiert schön mit den neuen
Möglichkeiten und ziert Euch nicht, Fragen, Verbesserungsvorschläge, Lob
oder sonstwas an die Purity-Macher oder an mich zu schicken.
Andreas Neumann - Auf dem Ruhbühl 151 - W 7997 Immenstaad
Bess dann !
© 28.12.1991 by Andreas Neumann für Gadget Amiga von Nils Kassube
und Purity von Steppenbrand und
Diesel